//------------------------------------------------------------------------------
//         Headers
//------------------------------------------------------------------------------
#include <string.h>
#include <stdio.h>

#include "main.h"
#include "fatfs.h"

#include "menu.h"
#include "st7789.h"

#include "wm8978.h"

#if 1
#include "audio.h"
#include "wav.h"
#include "flac.h"
#include "ape.h"
#endif

#define __AUDIO__ 1

// #define FONT_SIZE	24

static  DIR			dir;
static  FILINFO		fileinfo;

static  char        fname[128];
static  char        ext[8];

// dir and file list
SONGDIR				dir_list[MAX_DIR];
int					dir_size;
int 				dir_index;

SONGFILE			song_list[MAX_SONG];
int					song_size;
int					song_index;

int				isMenu;
int				isDir;
int				isSong;

#define MAX_LINE		6

static uint8_t	dir_pos, song_pos;

uint8_t		format;

uint8_t  sec;
uint8_t  min;

uint8_t volume = 0;

// extern  int		wm8978_volume;

uint8_t  play_state = STATE_STOP;
uint8_t  screen_mode  = MODE_DIR;

int Is_Process_button = 0;

uint8_t button;

static uint8_t get_filetype(char *filename);

static int dir_cmp(const void *a, const void *b);
static void dir_sort(void);
static int song_cmp(const void *a, const void *b);
static void song_sort(void);

extern void do_jpeg(int x, int y, char *fname);

#define SYSCLK_MHZ    (SystemCoreClock/1000000)		// 480Mhz

/**
  * @brief  The application .
  * @retval void
  */
static void play_delay(void)
{
	uint32_t Delay = 20000 * SYSCLK_MHZ;
	do {
		__NOP();
	} while (Delay --);

}

/**
  * @brief  The application .
  * @retval void
  */
static void audio_play(void)
{
	// 判断文件类型
	format = get_filetype(song_list[song_index].filename);
	sprintf(fname, "%s/%s", dir_list[dir_index].dirname, song_list[song_index].filename);
	// printf("filename : %s\r\n", fname);

	switch(format) {

	case 0x01:
		play_delay();
		// printf("play wav %s\r\n", fname);
#if __AUDIO__
		Wav_Play(fname);
#endif
		break;

	case 0x02:
		play_delay();
		// printf("play flac %s\r\n", fname);
#if __AUDIO__
	Flac_Play(fname);
#endif
		break;

	case 0x03:
		play_delay();
		// printf("play ape %s\r\n", fname);
#if __AUDIO__
	Ape_Play(fname);
#endif
		break;

	default:
		play_delay();
		printf("skip file %s ...\r\n", fname);
		Play_Next();
		break;
	}
}

/**
  * @brief  The application .
  * @retval void
  */
void Play_Next(void)
{
#if __AUDIO__
	audio_Stop();
	// f_close(&SDFile);
#endif
	
	if(song_index >= song_size && dir_index >= dir_size) {

		play_state = STATE_STOP;

	} else if(song_index >= song_size && dir_index < dir_size) {
		dir_index++;
		Build_Song_List(dir_list[dir_index].dirname);
		audio_play();

	} else {
		Show_Song(2);
		audio_play();
	}

}

/**
  * @brief  The application .
  * @retval void
  */
void Play_Prev(void)
{
#if __AUDIO__
	audio_Stop();
	// f_close(&SDFile);
#endif
	if(song_index <= 0 && dir_index <= 0) {
		play_state = STATE_STOP;

	} else if(song_index <= 0 && dir_index > 0 ) {
		dir_index--;
		Build_Song_List(dir_list[dir_index].dirname);
		audio_play();

	} else {
		Show_Song(1);
		audio_play();
	}
}

// show dir manu
void Show_Dir(int mode)
{
	unsigned char i;
	uint16_t dcolor, bgcolor;

	screen_mode  = MODE_DIR;

	switch (mode) {
	case 0:		// show begin
		
		menu_clean();
		dir_pos = 0;

		for(i = 0; i < MAX_LINE; i++) {
			if(i > dir_size)  break;
			if(i == dir_pos)	{
				dcolor = BLACK;
				bgcolor = MENU_COLOR;
			} else    {
				dcolor = MENU_COLOR;
				bgcolor = BLACK;
			}
			Lcd_String(0, i, dir_list[i].dirname, FONT_SIZE, dcolor, bgcolor);
		}
		break;

	case 1:		// show pre
		if( dir_index <= 0 ) break;

		dir_index--;

		if(dir_pos > 0) {
			Lcd_String(0, dir_pos, dir_list[dir_index + 1].dirname, FONT_SIZE, MENU_COLOR, BLACK);
			Lcd_String(0, dir_pos - 1, dir_list[dir_index].dirname, FONT_SIZE, BLACK, MENU_COLOR);
			dir_pos--;
		} else {
			for(i = 0; i < MAX_LINE; i++) {
				if((dir_index + i) > dir_size )  break;
				if(i == dir_pos)	{
					dcolor = BLACK;
					bgcolor = MENU_COLOR;
				} else    {
					dcolor = MENU_COLOR;
					bgcolor = BLACK;
				}
				Lcd_String(0, i, dir_list[dir_index + i].dirname, FONT_SIZE, dcolor, bgcolor);
			}
		}
		break;

	case 2:		// show next
		if( dir_index >= dir_size ) break;

		dir_index++;

		if(dir_pos < MAX_LINE - 1) {
			Lcd_String(0, dir_pos,   dir_list[dir_index - 1].dirname, FONT_SIZE, MENU_COLOR, BLACK);
			Lcd_String(0, dir_pos + 1, dir_list[dir_index].dirname,   FONT_SIZE, BLACK, MENU_COLOR);
			dir_pos++;
		} else {
			// dir_pos = MAX_LINE-1 = 3
			for(i = 0; i < MAX_LINE; i++) {
				if( (dir_index - dir_pos + i) > dir_size )  break;

				if(i == dir_pos)	{
					dcolor = BLACK;
					bgcolor = MENU_COLOR;
				} else    {
					dcolor = MENU_COLOR;
					bgcolor = BLACK;
				}
				Lcd_String(0, i, dir_list[dir_index - dir_pos + i].dirname, FONT_SIZE, dcolor, bgcolor);
			}
		}
		break;

	case 3:		// show cur
		for(i = 0; i < MAX_LINE; i++) {
			if( (dir_index - dir_pos + i) > dir_size )  break;
			if(i == dir_pos)	{
				dcolor = BLACK;
				bgcolor = MENU_COLOR;
			} else    {
				dcolor = MENU_COLOR;
				bgcolor = BLACK;
			}
			Lcd_String(0, i, dir_list[dir_index - dir_pos + i].dirname, FONT_SIZE, dcolor, bgcolor);
		}
		break;
	}
}

// build dir list
void Build_Dir_List(void)
{
	// taskENTER_CRITICAL(); //进入临界区
	
	memset(&dir, 0, sizeof(DIR));
	retSD = f_opendir(&dir, "");
	// iprintf("Directory of /:\n");
	printf("\r\nBuild_Albumn_List -> %d\r\n", retSD);

	dir_size = 0;
	while ( f_readdir( &dir, &fileinfo ) == FR_OK && fileinfo.fname[0] ) {
		// printf("%s ->%x\r\n", fileinfo.fname, fileinfo.fattrib);

		// only build directiry
		if(fileinfo.fattrib & AM_DIR) {
			if(strstr(fileinfo.fname, "System")) continue;
			memcpy(dir_list[dir_size].dirname, fileinfo.fname, sizeof(fileinfo.fname));
			printf("--dir-- %s\r\n", dir_list[dir_size].dirname);
			// MAX_DIR size
			if(dir_size++ >= MAX_DIR)  break;
		} else {
			printf("--file-- %s\r\n", fileinfo.fname);
		}
	}
	f_closedir(&dir);

	dir_size--;
	dir_index = 0;

	dir_sort();
	menu_clean();
	Show_Dir(0);
	// taskEXIT_CRITICAL(); //退出临界区
}

// show dir menu
void Show_Song(int mode)
{
	unsigned char i;

	uint16_t dcolor, bgcolor;

	screen_mode  = MODE_SONG;

	switch (mode) {
	case 0:		// show begin
		// Dispgraphic(0x00);
		song_pos = 0;
		for(i = 0; i < MAX_LINE; i++) {
			if(i > song_size)  break;
			if(i == song_pos)	{
				dcolor = BLACK;
				bgcolor = MENU_COLOR;
			} else    {
				dcolor = MENU_COLOR;
				bgcolor = BLACK;
			}
			Lcd_String(0, i, song_list[i].filename, FONT_SIZE, dcolor, bgcolor);
		}
		break;

	case 1:		// show pre
		if( song_index <= 0 ) break;

		song_index--;

		if(song_pos > 0) {
			Lcd_String(0, song_pos, song_list[song_index + 1].filename, FONT_SIZE, MENU_COLOR, BLACK);
			Lcd_String(0, song_pos - 1, song_list[song_index].filename, FONT_SIZE, BLACK, MENU_COLOR);
			song_pos--;
		} else {
			// LCD_clr();
			for(i = 0; i < MAX_LINE; i++) {
				if((song_index + i) > song_size )  break;
				if(i == song_pos)	{
					dcolor = BLACK;
					bgcolor = MENU_COLOR;
				} else    {
					dcolor = MENU_COLOR;
					bgcolor = BLACK;
				}
				Lcd_String(0, i, song_list[song_index + i].filename, FONT_SIZE, dcolor, bgcolor);
			}
		}
		break;

	case 2:		// show next
		if( song_index >= song_size ) break;

		song_index++;

		if(song_pos < MAX_LINE - 1) {
			Lcd_String(0, song_pos, song_list[song_index - 1].filename, FONT_SIZE, MENU_COLOR, BLACK);
			Lcd_String(0, song_pos + 1, song_list[song_index].filename, FONT_SIZE, BLACK, MENU_COLOR);
			song_pos++;
		} else {
			// LCD_clr();
			// dir_pos = MAX_LINE-1 = 3
			for(i = 0; i < MAX_LINE; i++) {
				if( (song_index - song_pos + i) > song_size )  break;
				if(i == song_pos)	{
					dcolor = BLACK;
					bgcolor = MENU_COLOR;
				} else    {
					dcolor = MENU_COLOR;
					bgcolor = BLACK;
				}
				Lcd_String(0, i, song_list[song_index - song_pos + i].filename, FONT_SIZE, dcolor, bgcolor);
			}
		}
		break;

	case 3:		// show cur
		// Dispgraphic(0x00);
		for(i = 0; i < MAX_LINE; i++) {
			if( (song_index - song_pos + i) > song_size )  break;
			if(i == song_pos)	{
				dcolor = BLACK;
				bgcolor = MENU_COLOR;
			} else    {
				dcolor = MENU_COLOR;
				bgcolor = BLACK;
			}
			Lcd_String(0, i, song_list[song_index - song_pos + i].filename, FONT_SIZE, dcolor, bgcolor);
		}
		break;
	}
}

// build song list
void Build_Song_List(char *dirname)
{
	printf("\r\nBuild_Song_List -> %s\r\n", dirname);

	// taskENTER_CRITICAL(); //进入临界区
	
	// memset(&dir, 0, sizeof(DIR));
	retSD = f_opendir(&dir, dirname);
	// iprintf("Directory of %s:\n", dirname);
	printf("open album [%s] ->%d\r\n", dirname, retSD);
	song_size = 0;
	while ( f_readdir( &dir, &fileinfo ) == FR_OK && fileinfo.fname[0] ) {
		printf("song -> %s\r\n", fileinfo.fname);
		memcpy(song_list[song_size].filename, fileinfo.fname, sizeof(fileinfo.fname));
		song_list[song_size].fsize = fileinfo.fsize;
		// song_list[song_size].filename[strlen(fileinfo.fname)-4] = 0x00;
		// song_list[song_size].fsize = fileinfo.fsize;
		// MAX_SONG size
		if(song_size++ >= MAX_SONG)  break;
	}

	song_size--;
	song_index = 0;

	song_sort();
	menu_clean();
	Show_Song(0);
	build_ooo();
	
	// taskEXIT_CRITICAL(); //退出临界区
}

// button PRE
void DO_Bp_UP(void)
{
	switch(screen_mode) {
	case MODE_PLAY:
		// Play_Prev();
		if(play_state == STATE_PAUSE) {

			if(volume > 1) volume--;
			// WM8978_HPvol_Set(volume, volume);	//耳机音量设置
		}
		break;

	case MODE_DIR:
		Show_Dir(1);
		break;

	case MODE_SONG:
		Show_Song(1);
		break;
	default :
		break;
	}
}

// button NEXT
void DO_Bp_DOWN(void)
{
	switch(screen_mode) {
	case MODE_PLAY:
		// Play_Next();
		if(play_state == STATE_PAUSE) {

			if(volume < 64) volume++;
			// WM8978_HPvol_Set(volume, volume);	//耳机音量设置
		}
		break;

	case MODE_DIR:
		Show_Dir(2);
		break;

	case MODE_SONG:
		Show_Song(2);
		break;
	default :
		break;
	}
}

/**
  * @brief  The application .
  * @retval void
  */
void DO_Bp_BACK(void)
{
	switch(play_state) {
	case STATE_PLAY:
		if(screen_mode == MODE_PLAY) {
#if __AUDIO__			
			audio_Stop();
#endif
			Play_Prev();
		}
		break;

	case STATE_PAUSE:
#if __AUDIO__
		audio_Stop();
#endif
	break;

	case STATE_STOP:
		if(screen_mode == MODE_PLAY) {
			// audio_play();
			Show_Song(3);
		} else if(screen_mode == MODE_DIR) {
			// Build_Song_List(dir_list[dir_index].dirname);
			Show_Dir(1);
		} else if(screen_mode == MODE_SONG) {
			// audio_play();
			if(song_index == 0) {
				Show_Dir(3);
			} else {
				Show_Song(1);
			}
		}
		break;
	default :
		break;
	}
}

/**
  * @brief  The application .
  * @retval void
  */
void DO_Bp_NEXT(void)
{
	switch(play_state) {
	case STATE_PLAY:
		if(screen_mode == MODE_PLAY) {
			play_state = STATE_STOP;
			// read_next_chunk = false;
			Play_Next();
		}
		break;

	case STATE_PAUSE:
#if __AUDIO__
	audio_Resume();
#endif
	
		break;

	case STATE_STOP:
		if(screen_mode == MODE_PLAY) {
			audio_play();
		} else if(screen_mode == MODE_DIR) {
			// Build_Song_List(dir_list[dir_index].dirname);
			Show_Dir(2);
		} else if(screen_mode == MODE_SONG) {
			// audio_play();
			Show_Song(2);
		}
		break;
	default :
		break;
	}
}

/**
  * @brief  The application .
  * @retval void
  */
void DO_Bp_OK(void)
{
	// printf("\r\n screen_mode: %02x  play_state: %02x\r\n", screen_mode, play_state);

	switch(screen_mode) {
	case MODE_PLAY:
		if (play_state == STATE_STOP) {
			audio_play();
		} else if (play_state == STATE_PLAY) {
#if __AUDIO__
			audio_Pause();
#endif
			
		} else {
#if __AUDIO__
			audio_Resume();
#endif
			
		}
		break;

	case MODE_DIR:
		Build_Song_List(dir_list[dir_index].dirname);
		break;

	case MODE_SONG:
		audio_play();
		break;

	default :
		break;
	}
}

/**
  * @brief  The application .
  * @retval void
  */
void DO_Bp_STOP(void)
{
	if(play_state == STATE_PLAY || play_state == STATE_PAUSE) {
#if __AUDIO__
		audio_Stop();
#endif
		
	}
	
	if(play_state == STATE_STOP) {
		if(screen_mode == MODE_PLAY)
			Show_Song(3);
		else
			Show_Dir(3);
	}
}


/**
  * @brief  The application .
  * @retval void
  */
void Menu_init(void)
{
	volume = 0;

	ST7789_Fill_Color(BLACK);
	
	printf("\r\n********** Begin mount SD **********\r\n\n");
	
	// memset(&fs, 0, sizeof(FATFS));
	printf("[fs_mount] -> %d\r\n\n", f_mount(&SDFatFS, "", 1));	// opt: 1 -> mount now
	Build_Dir_List();
	play_state = STATE_STOP;
	screen_mode  = MODE_DIR;
	
	// do_jpeg(0,   288, "button_back.jpg");
	// do_jpeg(120, 288, "button_stop.jpg");
	// do_jpeg(240, 288, "button_play.jpg");
	// do_jpeg(360, 288, "button_next.jpg");
	
	// do_jpeg(0, 0, "LCD480x320.jpg");
	
	// format = 0x01;
	// Wav_Play("24.wav");
	
	// format = 0x02;
	// Flac_Play("24.flac");
	
	// format = 0x03;
	// Ape_Play("16.ape");
	/***
	dis_char('0');
	dis_char('1');
	dis_char('2');
	dis_char('3');
	dis_char('4');
	dis_char('5');
	dis_char('6');
	dis_char('7');
	dis_char('8');
	dis_char('9');
	dis_char(':');
	***/
	
}

/**
  * @brief  The application .
  * @retval void
  */
void menu_clean(void)
{
	ST7789_Fill(0, 0, 320 - 1, 6 * 24 - 1, 0x0000);
}

/**
  * @brief  The application .
  * @retval void
  */
void menu_Start(void)
{
	play_state   = STATE_PLAY;
	screen_mode  = MODE_PLAY;
	
	sec = min = 0;
	dis_min(min);
	dis_sec(sec);
	dis_vol();
	
	dis_start();
}

/**
  * @brief  The application .
  * @retval void
  */
void menu_Pause(void)
{
	dis_pause();
	play_state = STATE_PAUSE;
	
}

/**
  * @brief  The application .
  * @retval void
  */
void menu_Resume(void)
{
	play_state = STATE_PLAY;
	dis_start();
}

/**
  * @brief  The application .
  * @retval void
  */
void menu_Stop(void)
{
	// disp  = 0;
	
	dis_stop();
	play_state = STATE_STOP;
	
}

/**
  * @brief  The application .
  * @retval void
  */
static uint8_t get_filetype(char *filename)
{
	char 	 *extension;
	char	ext[8];

	memset(ext, 0, 8);

	extension = strrchr(filename, '.');

	if(extension == NULL) {
		return 0xff;
	} else {
		extension++;
	}

	memcpy(ext, extension, strlen(extension));

	if( strcmp(ext, "wav") == 0) {
		return 0x01;
	} else if( strcmp(ext, "flac") == 0) {
		return 0x02;
	} else if( strcmp(ext, "ape") == 0) {
		return 0x03;
	} else {
		return 0x00;
	}
}

/**
  * @brief  The application .
  * @retval void
  */
static int dir_cmp(const void *a, const void *b)
{
	SONGDIR *p1 = (SONGDIR *)a;
	SONGDIR *p2 = (SONGDIR *)b;

	return strcmp(p1->dirname, p2->dirname);
}

/**
  * @brief  The application .
  * @retval void
  */
static void dir_sort(void)
{
	qsort(dir_list, dir_size + 1, sizeof(SONGDIR), dir_cmp);
}

/**
  * @brief  The application .
  * @retval void
  */
static int song_cmp(const void *a, const void *b)
{
	SONGFILE *p1 = (SONGFILE *)a;
	SONGFILE *p2 = (SONGFILE *)b;

	return strcmp(p1->filename, p2->filename);
}

/**
  * @brief  The application .
  * @retval void
  */
static void song_sort(void)
{
	qsort(song_list, song_size + 1, sizeof(SONGFILE), song_cmp);
}


/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/



